#include "widget.h"
#include "ui_widget.h"

#include <QDebug>
#include <QMessageBox>
#include <QDesktopWidget>
#include <QClipboard>
#include "filedialog.h"
#include <QDialogButtonBox>
#include <QStyle>

#define SEARCH_TAB			0
#define ADV_SEARCH_TAB		1
#define DICT_TAB			2
#define ABOUT_TAB			3




//--------------------------------
Widget::Widget (QWidget *parent) :
	QWidget (parent),
	ui (new Ui::Widget)
{
	ui->setupUi (this);

	ui->resultList->setLayoutMode (QListView::Batched);
	ui->resultList->setBatchSize (200);
	ui->resultList->setUniformItemSizes (true);
	ui->resultList->setAlternatingRowColors (true);

	ui->advancedResultList->setLayoutMode (QListView::Batched);
	ui->advancedResultList->setBatchSize (200);
	ui->advancedResultList->setUniformItemSizes (true);
	ui->advancedResultList->setAlternatingRowColors (true);

	ui->message->clear ();
	ui->copyButton->setDisabled (true);
	ui->progressBar->setVisible (false);
	ui->distLabel->setVisible (false);
	ui->distSpinBox->setVisible (false);
	ui->distSpinBox->setValue (1);

	m_config = new Config (this);

	m_dico = new Dico (this, m_config->useDamerauTest ());


	m_letterList.clear ();

	ui->messageAdvanced->clear ();

	// System Tray Icon
	if (QSystemTrayIcon::isSystemTrayAvailable ())
	{
		m_systemTrayIcon = new QSystemTrayIcon (Config::appIcon (), this);
		m_systemTrayIcon->setVisible (true);
		// STI menu
		m_STIMenu = new QMenu (this);
		QAction* action = new QAction (tr ("Quitter"), this);
		action->setIcon (QIcon::fromTheme ("application-exit", QIcon (":/images/application-exit.svg")));
		m_STIMenu->addAction (action);
		connect (action,
				 SIGNAL (triggered ()),
				 qApp,
				 SLOT (quit ()));
		m_systemTrayIcon->setContextMenu (m_STIMenu);
		connect (m_systemTrayIcon,
				 SIGNAL (activated (QSystemTrayIcon::ActivationReason)),
				 this,
				 SLOT (onSystemTrayIconActivated (QSystemTrayIcon::ActivationReason)));
	}
	else
	{
		ui->hideButton->setVisible (false);
	}

	// Ui

//    QStyle* style = qApp->style ();
	ui->hideButton->setIcon (qApp->style ()->standardIcon (QStyle::SP_TitleBarMinButton));

	ui->clearButton->setIcon (QIcon::fromTheme ("edit-clear", QIcon (":/images/edit-clear.svg")));
	ui->advancedClearButton->setIcon (QIcon::fromTheme ("edit-clear", QIcon (":/images/edit-clear.svg")));
	ui->addTheWord->setIcon (QIcon::fromTheme ("list-add", QIcon (":/images/list-add.svg")));
	ui->copyButton->setIcon (QIcon::fromTheme ("edit-copy", QIcon (":/images/edit-copy.svg")));
	ui->advancedSearch->setIcon (QIcon::fromTheme ("edit-find", QIcon (":/images/edit-find.svg")));
	ui->advancedCopyButton->setIcon (QIcon::fromTheme ("edit-copy", QIcon (":/images/edit-copy.svg")));
	ui->advancedCopyButton->setDisabled (true);
	ui->changeRefDic->setIcon (QIcon::fromTheme ("preferences-desktop-locale", QIcon ("://images/preferences-desktop-locale.svg")));
	ui->tabWidget->setIconSize (QSize (24, 24));
	ui->tabWidget->setTabIcon (SEARCH_TAB, QIcon::fromTheme ("edit-find", QIcon (":/images/edit-find.svg")));
	ui->tabWidget->setTabIcon (ADV_SEARCH_TAB, QIcon (":/images/scrabble.png"));
	ui->tabWidget->setTabIcon (DICT_TAB, Config::dicIcon ());
	ui->tabWidget->setTabIcon (ABOUT_TAB, QIcon::fromTheme ("help-about", QIcon ("://images/help-about.svg")));
	ui->clearAllDics->setIcon (QIcon::fromTheme ("user-trash", QIcon (":/images/user-trash.svg")));
	ui->addADic->setIcon (QIcon::fromTheme ("list-add", QIcon (":/images/list-add.svg")));
	ui->saveRefDic->setIcon (QIcon::fromTheme ("document-save-as", QIcon (":/images/document-save-as.svg")));

	ui->copyButton->setDisabled (true);

	connect (ui->wordLength,
			 SIGNAL (valueChanged (int)),
			 this,
			 SLOT (resizeCb (int)));
	connect (ui->hideButton,
			 SIGNAL (clicked ()),
			 this,
			 SLOT (hide ()));
	connect (ui->addTheWord,
			 SIGNAL (clicked ()),
			 this,
			 SLOT (onAddTheWordClicked ()));
	connect (ui->wordToAdd,
			 SIGNAL (textChanged (QString)),
			 this,
			 SLOT (onWordToAddChanged (QString)));
	connect (ui->clearButton,
			 SIGNAL (clicked ()),
			 this,
			 SLOT (onClearButtonClicked ()));
	connect (ui->copyButton,
			 SIGNAL (clicked ()),
			 this,
			 SLOT(onCopyButtonClicked()));
	connect (ui->advancedCopyButton,
			 SIGNAL (clicked ()),
			 this,
			 SLOT(onAdvancedCopyButtonClicked()));
	connect (ui->anyLength,
			 SIGNAL(toggled(bool)),
			 this,
			 SLOT(find()));
	connect (ui->advancedSearch,
			 SIGNAL(clicked()),
			 this,
			 SLOT(onAdvancedSearchClicked()));
	connect (ui->wordToSearch,
			 SIGNAL(returnPressed()),
			 this,
			 SLOT(onAdvancedSearchClicked()));
	connect (ui->tabWidget,
			 SIGNAL(currentChanged(int)),
			 this,
			 SLOT(onCurrentTabChanged(int)));
	connect (ui->advancedClearButton,
			 SIGNAL(clicked()),
			 this,
			 SLOT(onAdvancedClearButtonClicked()));
	connect (ui->sortByLength,
			 SIGNAL(toggled(bool)),
			 this,
			 SLOT(onAdvancedSearchClicked()));
	connect (ui->changeRefDic,
			 SIGNAL(clicked()),
			 this,
			 SLOT(onChooseRefDicClicked()));
	connect (ui->refDicsList,
			 SIGNAL(currentIndexChanged(QString)),
			 this,
			 SLOT(onRefDicsListCurrentChanged(QString)));
	connect (ui->addADic,
			 SIGNAL(clicked()),
			 this,
			 SLOT(onAddADicClicked()));
	connect (ui->clearAllDics,
			 SIGNAL(clicked()),
			 this,
			 SLOT(onClearAllDics()));
	connect (ui->saveRefDic,
			 SIGNAL(clicked()),
			 this,
			 SLOT(onSaveRefDic()));
	connect (ui->searchOptions,
			 SIGNAL(currentIndexChanged(int)),
			 this,
			 SLOT(onSearchOptionsCurrentIndexChanged(int))
			 );
	connect (m_dico,
			 SIGNAL(xMessage(bool, QStringList, QString)),
			 this,
			 SLOT(onDicoXMessage(bool, QStringList, QString)));
	connect (m_dico,
			 SIGNAL (error (QString)),
			 this,
			 SLOT (onDicoError (QString)));
	connect (m_dico,
			 SIGNAL(dicoInfos(int,int)),
			 this,
			 SLOT (setMinMaxLength (int,int)));
	connect (m_dico,
			 SIGNAL (message (QString)),
			 this,
			 SLOT (onDicoMessage (QString)));
	connect (m_dico,
			 SIGNAL(initCalc(int)),
			 this,
			 SLOT(onDicoInitCalc(int)));
	connect (m_dico,
			 SIGNAL(progress(int)),
			 this,
			 SLOT(onDicoProgress(int)));
	connect (m_dico,
			 SIGNAL(stopCalc(int)),
			 this,
			 SLOT(onDicoStopCalc(int)));

	ui->versionDisplay->setReadOnly (true);
	ui->versionDisplay->setAlignment (Qt::AlignCenter);

	ui->addTheWord->setDisabled (true);

	// centrage sur l'écran
	QDesktopWidget dw;
	QRect screen (dw.screenGeometry ());
	setGeometry (screen.center ().x () - width () / 2,
				 screen.center ().y () - height () / 2,
				 width (),
				 height ());

	// titre
	setWindowTitle (tr ("Aide pour les jeux de lettres"));

	// icône
	setWindowIcon (Config::appIcon ());

	// chargement du dernier dico
	m_dico->init (Config::refDicsPath () + m_config->currentRefDico ());
//    int tmp = m_dico->averageLength ();
//    ui->wordLength->setValue (tmp);

	ui->wordLength->setValue (m_config->letterCount ());

	// positionnement sur le premier onglet
	ui->tabWidget->setCurrentIndex (SEARCH_TAB);
}
//----------------
Widget::~Widget ()
{
//    QApplication::clipboard ()->clear ();
	delete ui;
	delete m_dico;
	//	delete m_systemTrayIcon;
	delete m_config;
}
//------------------------------------------------------------------------------
void Widget::onSystemTrayIconActivated (QSystemTrayIcon::ActivationReason reason)
{
	switch (reason)
	{
		case QSystemTrayIcon::Context:		// The context menu for the system tray entry was requested
		break;

		case QSystemTrayIcon::Unknown:		// Unknown reason
		case QSystemTrayIcon::DoubleClick:	// The system tray entry was double clicked
		case QSystemTrayIcon::Trigger:		// The system tray entry was clicked
		case QSystemTrayIcon::MiddleClick:	// The system tray entry was clicked with the middle mouse button
			activateWindow ();
			raise ();
			show ();
		break;

		default:
		break;
	}
}

//-----------------------------
void Widget::resizeCb (int num)
{
	while (m_letterList.size () > num)
	{
		LetterEdit* letter = m_letterList.last ();
		disconnect (letter, SIGNAL (letterChanged (QChar)), this, SLOT (find ()));
		ui->lettersLayout->removeWidget (letter);
		delete m_letterList.takeLast ();
	}

	while (m_letterList.size () < num)
	{
		LetterEdit* letter = new LetterEdit (this);
		ui->lettersLayout->addWidget (letter);
		m_letterList << letter;
		connect (letter, SIGNAL (letterChanged (QChar)), this, SLOT (find ()));
	}

	m_config->setLetterCount (num);

	find ();
}
//------------------
void Widget::find ()
{

	QString toFind;

	bool isEmpty = true;

	foreach (LetterEdit* letterWidget, m_letterList)
	{
		QChar letter = letterWidget->letter ();
		toFind += letter;
		if (letter != Config::m_blankDisplay) isEmpty = false;
	}

	if (isEmpty)
	{
		onClearButtonClicked ();
		return;
	}

	toFind.replace (Config::m_blankDisplay, Config::m_joker);

	m_dico->find (toFind, ui->anyLength->isChecked ());
}
//--------------------------------------------
void Widget::setMinMaxLength (int min, int max)
{
	ui->wordLength->setMinimum (min);
	ui->wordLength->setMaximum (max);
//    ui->wordLength->setValue (m_dico->averageLength ());
}
//--------------------------------
void Widget::onAddTheWordClicked ()
{
	m_dico->addToAnnexe (ui->wordToAdd->text ());
	m_dico->addFrom (Config::annexeDico ());

	ui->wordToAdd->clear ();

	find ();
}
//----------------------------------------------
void Widget::onWordToAddChanged (const QString &newWord)
{
	ui->addTheWord->setDisabled (newWord.isEmpty ());
}
//-------------------------------------
void Widget::onDicoMessage (const QString & msg)
{
	ui->message->setText (msg);
}
//-----------------------------------
void Widget::onDicoError (const QString & err)
{
	QMessageBox::warning (this, qApp->applicationName (), err);
}
//---------------------------------
void Widget::onClearButtonClicked ()
{
	foreach (LetterEdit* letter, m_letterList)
	{
		letter->clear ();
	}
	m_resultList.clear ();
	ui->resultList->clear ();
	ui->copyButton->setEnabled (false);
	ui->message->clear ();
}
//---------------------------------
void Widget::onCopyButtonClicked()
{
	QClipboard *clipboard = QApplication::clipboard();

	QString toCopy = m_resultList.join ("\n");

	if (! toCopy.isEmpty ())
		clipboard->setText (toCopy);
}
//----------------------------------------
void Widget::onAdvancedCopyButtonClicked()
{
	QClipboard *clipboard = QApplication::clipboard();

	QString toCopy = m_advancedResultList.join ("\n");

	if (! toCopy.isEmpty ())
		clipboard->setText (toCopy);
}
//------------------------------------
void Widget::prepareAdvancedResults ()
{
	ui->messageAdvanced->setText (tr ("Recherche en cours..."));
}
//-------------------------------------
void Widget::onAdvancedSearchClicked ()
{
	QString target (ui->wordToSearch->text ().toLatin1 ().toUpper ());
	if (target.isEmpty ()) return;

	prepareAdvancedResults ();
	int index = ui->searchOptions->currentIndex ();

	if (index == Dico::RegExp || index == Dico::Jokers)
	{
		QRegExp regExp (target,
						Qt::CaseSensitive,
						(index == Dico::RegExp ? QRegExp::RegExp2 : QRegExp::Wildcard) );

		if (!regExp.isValid ())
		{
			QMessageBox::warning (this,
								  tr ("Recherche avancée"),
								  tr ("L'expression n'est pas valide")
								  );
			return;
		}

		m_dico->find (regExp, true);
	}
	else
	{
		if (index == Dico::DistantFrom)
			m_dico->find (target, index, ui->distSpinBox->value ());
		else
			m_dico->find (target, index);
	}

}
//------------------------------------------
void Widget::onAdvancedClearButtonClicked ()
{
	m_advancedResultList.clear ();
	ui->wordToSearch->clear ();
	ui->advancedResultList->clear ();
	ui->advancedCopyButton->setDisabled (true);
	ui->wordToSearch->setFocus ();
	ui->messageAdvanced->clear ();
}

//-------------------------------------------
void Widget::onCurrentTabChanged (int newTab)
{
	switch (newTab)
	{
		case SEARCH_TAB:
			ui->wordLength->setFocus ();
			ui->wordLength->selectAll ();
		break;

		case ADV_SEARCH_TAB:
			ui->wordToSearch->setFocus ();
		break;

		case DICT_TAB:
		{
			ui->refDicsList->clear ();

			QMap<QString, QIcon> list (m_dico->refDicosList ());
			foreach (const QString& item, list.keys ())
			{
				ui->refDicsList->addItem (list.value (item),	// l'icône
										  item);				// le texte (fr, de, etc...)
			}
			int index = ui->refDicsList->findText (m_dico->currentRefDico ());
			ui->refDicsList->setCurrentIndex (index);
			ui->changeRefDic->setDisabled (true);
			ui->keepAnnexe->setChecked (true);
			ui->keepAnnexe->setDisabled (true);
		}
		break;

		case ABOUT_TAB:
			ui->versionDisplay->setText (tr ("Version %1 - actuellement %2 mots en mémoire")
										 .arg (qApp->applicationVersion ())
										 .arg (m_dico->size ()));
		break;

	}

}
//----------------------------------
void Widget::onChooseRefDicClicked ()
{
	QString dicoName (ui->refDicsList->currentText ());

	m_dico->init (Config::refDicsPath () + dicoName, ui->keepAnnexe->isChecked ());
	m_config->setCurrentRefDico (dicoName);
	onCurrentTabChanged (DICT_TAB);
}
//-----------------------------------------------------------
void Widget::onRefDicsListCurrentChanged (const QString& newCurrent)
{
	bool mustDisable = (newCurrent == m_dico->currentRefDico ());
	ui->changeRefDic->setDisabled (mustDisable) ;
	ui->keepAnnexe->setDisabled (mustDisable);
}
//------------------------------
void Widget::onAddADicClicked ()
{
	FileDialog fd (this);

	fd.setDefaultSuffix ("dic");

	QString dicoPath = fd.getOpenFileName (this,
										   tr ("Ajouter un dictionnaire"),
										   Config::userHomePath (),
										   "*.dic",
										   0,
										   QFileDialog::HideNameFilterDetails
										   | QFileDialog::ReadOnly
										   | QFileDialog::DontUseNativeDialog);
	qApp->processEvents ();

	if (dicoPath.isEmpty ()) return;

	QFile fileToOpen (dicoPath);
	if (fileToOpen.exists ())
	{
		m_dico->addFrom (dicoPath);
	}

	onCurrentTabChanged (DICT_TAB);
}
//----------------------------
void Widget::onClearAllDics ()
{
	QMessageBox msgBox;

	msgBox.setText (tr ("Cette opération va effacer tous les dictionnaires\nactuellement chargés"));
	msgBox.setStandardButtons (QMessageBox::Cancel);
	QPushButton *continueButton = msgBox.addButton(tr ("Effacer tout"), QMessageBox::ActionRole);
	msgBox.setDefaultButton (QMessageBox::Cancel);
	msgBox.setIcon (QMessageBox::Warning);

	msgBox.exec ();

	if (msgBox.clickedButton () != continueButton)  return;

	m_dico->clear ();
	onCurrentTabChanged (DICT_TAB);
}
//--------------------------
void Widget::onSaveRefDic ()
{
	QString dicName = FileDialog::getSaveFileName (this,
												   tr ("Enregistrer le référentiel"),
												   Config::refDicsPath (),
												   "*.dic",
												   0,
												   QFileDialog::DontUseNativeDialog,
												   "dic");

	if (dicName.isEmpty ()) return;

	QFileInfo fileInfo (dicName);

	if (m_dico->officialRefDicosList ().contains (fileInfo.fileName ()) &&
		Config::refDicsPath ().startsWith (fileInfo.absolutePath ()) )
	{
		if (m_config->alertOverwriteReference ())
		{
			QMessageBox::warning (this,
								  qApp->applicationName (),
								  tr ("L'enregistrement sous ce nom n'est pas autorisé\ncar votre dictionnaire serait automatiquement remplacé\npar l'original au prochain redémarrage de mcroises.")
								  );
			m_config->setAlertOverWriteReference (false);
			return;
		}
	}

	m_dico->save (dicName);

	onCurrentTabChanged (DICT_TAB);
}
//----------------------------------------------------------------------------------------
void Widget::onDicoXMessage(const bool extended, const QStringList &fromDico, const QString& txt)
{

	QStringList* resultList;
	QLabel* messageLocation;
	QPushButton* copyButton;
	QListWidget* listWidget;

	if (not extended)
	{
		resultList = &m_resultList;
		messageLocation = ui->message;
		copyButton = ui->copyButton;
		listWidget = ui->resultList;
	}
	else
	{
		resultList = &m_advancedResultList;
		messageLocation = ui->messageAdvanced;
		copyButton = ui->advancedCopyButton;
		listWidget = ui->advancedResultList;
	}


	*resultList = fromDico;

	if (extended)
	{
		if (ui->sortByLength->isChecked ())
		{
			QMap<int, QString> map;

			foreach (const QString& word, *resultList)
			{
				map.insertMulti (word.length (), word);
			}

			*resultList = map.values ();
		}
		else
		{
			resultList->sort ();
		}
	}

	int size = resultList->size ();

	copyButton->setDisabled (true);
	listWidget->clear ();
	listWidget->addItems (*resultList);

	QString mess;

	switch (size)
	{
		case 0:
			mess = tr ("Aucun résultat");
		break;

		case 1:
			mess = tr ("Une correspondance trouvée");
		break;

		default:
			mess = tr ("%1 correspondances trouvées").arg (size);
		break;
	}

	if (m_config->displayExecTime ()) {
		mess += tr (" en %1 ms").arg (m_msTimeCalc);
	}

	if (not txt.isEmpty ()) {
		mess += txt;
	}

	messageLocation->setText (mess);
	copyButton->setDisabled (size == 0);

}
//--------------------------------------------------------
void Widget::onSearchOptionsCurrentIndexChanged (const int index)
{
	ui->distLabel->setVisible (index == Dico::DistantFrom);
	ui->distSpinBox->setVisible (index == Dico::DistantFrom);
}
//-----------------------------------
void Widget::onDicoInitCalc (const int max)
{
	ui->progressBar->setValue (0);
	ui->progressBar->setMaximum (max);
	m_msTimeCalc = 0;
}
//------------------------------------
void Widget::onDicoProgress (const int step)
{
	ui->progressBar->setValue (step);
	ui->progressBar->show ();
}
//----------------------------
void Widget::onDicoStopCalc (const int msElapsed)
{
	ui->progressBar->hide ();
	m_msTimeCalc = msElapsed;
}

